package cn.ticsmyc.tools.framework.ioc.factory;

import cn.ticsmyc.tools.framework.ioc.entity.BeanDefinition;
import cn.ticsmyc.tools.framework.ioc.entity.BeanReference;
import cn.ticsmyc.tools.framework.ioc.entity.PropertyValue;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;

/**
 * 创建Bean的同时，自动完成属性的注入
 *
 * @author Ticsmyc
 * @date 2021-04-22 16:35
 */
public class AutowiredCapableBeanFactory extends AbstractBeanFactory {

    @Override
    protected Object doCreateBean(BeanDefinition beanDefinition) throws Exception {
        if(beanDefinition.getSingleton() && beanDefinition.getBean() != null) {
            return beanDefinition.getBean();
        }
        Object bean = beanDefinition.getBeanClass().newInstance();
        if(beanDefinition.isSingleton()) {
            beanDefinition.setBean(bean);
        }
        applyPropertyValues(bean, beanDefinition);
        return bean;
    }

    /**
     * 为Bean注入属性
     *
     * @param bean
     * @param beanDefinition
     */
    private void applyPropertyValues(Object bean, BeanDefinition beanDefinition) throws Exception {
        List<PropertyValue> propertyValueList = beanDefinition.getPropertyValues().getPropertyValueList();
        for (PropertyValue propertyValue : propertyValueList) {

            Field field = bean.getClass().getDeclaredField(propertyValue.getName());
            Object value = propertyValue.getValue();

            //如果要注入的value是容器中的另一个Bean
            if(value instanceof BeanReference) {
                BeanReference beanReference = (BeanReference) value;
                BeanDefinition refBeanDefinition = beanDefinitionMap.get(beanReference.getBeanId());
                if(refBeanDefinition == null){
                    throw new RuntimeException("找不到 "+beanReference.getBeanId()+" 的beanDefinition ");
                }
                if(refBeanDefinition.isSingleton()){
                    if(refBeanDefinition.getBean()!=null){
                        value = refBeanDefinition.getBean();
                    }else{
                        value = doCreateBean(refBeanDefinition);
                    }
                }else{
                    //先把自己放入earlyBean
                    if(earylyBean.get() == null){
                        earylyBean.set(new HashMap<>());
                    }
                    if(!earylyBean.get().containsKey(beanDefinition.getBeanClassName())){
                        earylyBean.get().put(beanDefinition.getBeanClassName(),bean);
                    }
                    //再尝试获取所需的Bean
                    value = getBean(beanReference.getBeanId());
                }

            }
            field.setAccessible(true);
            field.set(bean, value);
        }
        //如果自己在earlyBean里，就删除
        if(earylyBean.get()!=null && earylyBean.get().containsKey(beanDefinition.getBeanClassName())){
            earylyBean.get().remove(beanDefinition.getBeanClassName());
        }
    }

}
